
#ifndef IFACTORY_H
#define IFACTORY_H

#include "../common.hpp"

#include "../iapplication.hpp"
#include "iiapplication.hpp"

#include "../iwidgets.hpp"
#include "iiwidgets.hpp"

#include <typeinfo>

extern "C" {
#define MWINCLUDECOLORS
#include <TinyWidgets/tnWidgets.h>
}

//////////////////////
// Abstract Factory //
//////////////////////

class Ifactory {

#define factory_virtual_func(ELMNT) \
	virtual I##ELMNT* make##ELMNT(IWidget *, const char *label, int x, int y) = 0;

protected:
	IApplication *app;

public:

	class_iexception(IFactoryAppNotSet, "Application not set; use IApplication::setAPP()");
	
	virtual IApplication* makeApplication(int &argc, char **argv) = 0;
	
	virtual IWindow* mainWindow(const char *, int, int) = 0;

	virtual IWindow* makeWindow(const char *, int, int) = 0;

	factory_virtual_func(Button)
	factory_virtual_func(Label)
	factory_virtual_func(CheckButton)	
	factory_virtual_func(RadioGroup)
	factory_virtual_func(RadioButton)
	factory_virtual_func(RawWidget)

	virtual ITextBox* makeTextBox(IWidget *, const char *label, int x, int y, ITextBox::Mode) = 0;

	virtual IScrollbar* makeScrollbar(IWidget *, const char *label, int x, int y, 
		int min, int max, int step, int page, IScrollbar::Orientation) = 0;

	virtual IProgressBar* makeProgressBar(IWidget *, const char *, int x, int y, int min, int max, int step) = 0;
	
	// need to be called after IApplication has been allocated in application
	void setApp(IApplication *appl) {
		app = appl;
	}

	IApplication& getApp() const {
		return *app;
	}
};

////////////////////////
// Specific factories //
////////////////////////

// Qt factory

class QIfactory : public Ifactory {

#define qfactory_template(ELMNT) \
	I##ELMNT* make##ELMNT(IWidget *parent, const char *label, int x, int y) {\
		const QString lbl(label);\
		return new QI##ELMNT(dynamic_cast<QIWidget*>(parent), lbl, x, y);\
	}

public:
	IApplication* makeApplication(int &argc, char **argv) {
		return new QIApplication(argc, argv);
	}

	IWindow* mainWindow(const char *title, int x, int y)
	{
		// todo: exception
		return new QIMainWindow(title, x, y);
	}

	IWindow* makeWindow(const char *title, int x, int y)
	{
		if(!app) throw IFactoryAppNotSet();// todo: tnw also			
		return new QIWindow(NULL, title, x, y);
	}

	qfactory_template(Button)
	qfactory_template(Label)
	qfactory_template(CheckButton)
	qfactory_template(RadioGroup)
	qfactory_template(RadioButton);
	qfactory_template(RawWidget);

	ITextBox* makeTextBox(IWidget *parent, const char *, int x, int y, ITextBox::Mode mode)
	{
		return new QITextBox(dynamic_cast<QIWidget*>(parent), "", x, y, mode);
	}

	IScrollbar* makeScrollbar(IWidget *parent, const char *label, int x, int y, 
		 	int min, int max, int step, int page, IScrollbar::Orientation o)
	{
		return new QIScrollbar(dynamic_cast<QIWidget*>(parent),  x, y, min, max, step, page, o);
	}

	IProgressBar* makeProgressBar(IWidget *parent, const char *, int x, int y, int min, int max, int step) 
	{
		return new QIProgressBar(dynamic_cast<QIWidget*>(parent),  x, y, min, max, step);
	}
};

// TNW++ factory

class TIfactory : public Ifactory {

#define tfactory_template(ELMNT) \
	I##ELMNT* make##ELMNT(IWidget *parent, const char *label, int x, int y) {\
		return new TI##ELMNT(label, dynamic_cast<TIWidget*>(parent), x, y); \
	}

private:
	
	class TICloseActionHandler : public IActionHandler
	{
	public:
		void handler(IWidget &) {
			tnEndApp();
		}
	};

	class TIWindowCloseActionHandler : public IActionHandler
	{
	public:
		void handler(IWidget &window)
		{
			window.hide();
		}
	};
	

	TICloseActionHandler ticah;
	TIWindowCloseActionHandler twcah;

public:

	IApplication* makeApplication(int &argc, char **argv)
	{
		return new TIApplication(argc, argv);
	}

	IWindow* mainWindow(const char *title, int x, int y);
	
	IWindow* makeWindow(const char *title, int x, int y);

	
	tfactory_template(Button)
	tfactory_template(Label)
	tfactory_template(CheckButton)
	tfactory_template(RadioGroup)
	tfactory_template(RadioButton)
	tfactory_template(RawWidget)

	ITextBox* makeTextBox(IWidget *p, const char *label, int x, int y, ITextBox::Mode mode) 
	{
		return new TITextBox(label, dynamic_cast<TIWidget*>(p), x, y, mode);
	}

	IScrollbar* makeScrollbar(IWidget *p, const char *label, int x, int y,
		int min, int max, int step, int page, IScrollbar::Orientation o) 
	{
		return new TIScrollbar(label, dynamic_cast<TIWidget*>(p), x, y, min, max, step, page, o);	
	}

	IProgressBar* makeProgressBar(IWidget *parent, const char *, int x, int y, int min, int max, int step)
	{
		return new TIProgressBar(dynamic_cast<TIWidget*>(parent), x, y, min, max, step);
	}
};

#endif
